cmake_minimum_required(VERSION 3.12)
project(RTSeis VERSION 0.2.1 LANGUAGES CXX)
enable_testing()

##########################################################################################
#              Define the compiler standard, OpenMP, and Python, and GTest               #
##########################################################################################
include(FindOpenMP QUIET)
if (OPENMP_FOUND)
   message("OpenMP found")
   string(APPEND CMAKE_C_FLAGS   " ${OpenMP_C_FLAGS}")
   string(APPEND CMAKE_CXX_FLAGS " ${OpenMP_CXX_FLAGS} -fPIC")
endif()

include(CheckCXXCompilerFlag)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

option(BUILD_SHARED_LIBS "Build rtseis as .so" ON)
option(ADD_TEST "Add test option" ON)

message("Compling with CXX Flags: ${CMAKE_CXX_FLAGS}")

if (RTSEIS_WRAP_PYTHON)
   find_package(PythonInterp 3)
   find_package(PythonLibs 3 REQUIRED)
   message(STATUS "PYTHON_LIBRARIES = ${PYTHON_LIBRARIES}")
   message(STATUS "PYTHON_EXECUTABLE = ${PYTHON_EXECUTABLE}")
   message(STATUS "PYTHON_INCLUDE_DIRS = ${PYTHON_INCLUDE_DIRS}")
   find_package(pybind11 REQUIRED)
endif()

##########################################################################################
#                               Define the path to find IPP and MKL                      #
##########################################################################################
set(IPP_LIB_DIR "${IPP_ROOT}/lib/intel64")
set(IPP_INC_DIR "${IPP_ROOT}/include")
set(MKL_LIB_DIR "${MKL_ROOT}/lib/intel64")
set(MKL_INC_DIR "${MKL_ROOT}/include")

set(IPP_DIR ${CMAKE_CURRENT_LIST_DIR}/CMakeModules)
set(MKL_DIR ${CMAKE_CURRENT_LIST_DIR}/CMakeModules)

if(ADD_TEST)
   find_package(GTest REQUIRED)
endif()

find_package(IPP REQUIRED)
find_package(MKL REQUIRED)

##########################################################################################
#                                       Include Directories                              #
##########################################################################################

include_directories(
   ${CMAKE_CURRENT_SOURCE_DIR}/include
   ${IPP_INC_DIR}
   ${MKL_INC_DIR}
)
set(PRIVATE_INCLUDE_DEPENDS ${IPP_INC_DIR} ${MKL_INC_DIR})
message("Include directories:" ${PRIVATE_INCLUDE_DEPENDS})

##########################################################################################
#                                        Sort Out Python Wrappers                        #
##########################################################################################
IF (RTSEIS_WRAP_PYTHON)
   add_library(pyrtseis MODULE
               python/pyrtseis.cpp
               python/filterRepresentations.cpp
               python/waveform.cpp)
   target_link_libraries(pyrtseis PRIVATE pybind11::module rtseis)
ENDIF()

##########################################################################################
#                                      Define Library Dependencies                       #
##########################################################################################

configure_file(${CMAKE_CURRENT_LIST_DIR}/include/private/version.hpp.in
               ${CMAKE_CURRENT_LIST_DIR}/include/rtseis/version.hpp)
set(PUBLIC_HEADER_DIRECTORIES
    include/rtseis)
set(PRIVATE_HEADER_DIRECTORIES
    include/private)
set(LIBALL ${MKL_LIBRARY} ${IPP_LIBRARY})
set(LIBALL_PYTHON rtseis ${LIBALL} ${PYTHON_LIBRARIES})

SET(UTILS_SRCS
    src/utilities/version.cpp
    src/utilities/verbosity.cpp
    src/utilities/characteristicFunction/classicSTALTA.cpp
    src/utilities/characteristicFunction/carlSTALTA.cpp
    src/utilities/deconvolution/instrumentResponse.cpp
    src/utilities/filterDesign/filterDesigner.cpp
    src/utilities/filterDesign/response.cpp
    src/utilities/filterDesign/iir.cpp
    src/utilities/filterDesign/fir.cpp
    src/utilities/filterDesign/analogProtype.cpp
    src/utilities/filterDesign/windowFunctions.cpp
    src/utilities/filterRepresentations/ba.cpp
    src/utilities/filterRepresentations/fir.cpp
    src/utilities/filterRepresentations/sos.cpp
    src/utilities/filterRepresentations/zpk.cpp
    src/utilities/filterImplementations/decimate.cpp
    src/utilities/filterImplementations/detrend.cpp
    src/utilities/filterImplementations/downsample.cpp
    src/utilities/filterImplementations/firFilter.cpp
    src/utilities/filterImplementations/multiRateFIRFilter.cpp
    src/utilities/filterImplementations/iirFilter.cpp
    src/utilities/filterImplementations/iiriirFilter.cpp
    src/utilities/filterImplementations/medianFilter.cpp
    src/utilities/filterImplementations/sos.cpp
    src/utilities/interpolation/cubicSpline.cpp
    src/utilities/interpolation/interpolate.cpp
    src/utilities/interpolation/linear.cpp
    src/utilities/interpolation/weightedAverageSlopes.cpp
    src/utilities/math/convolve.cpp
    src/utilities/math/polynomial.cpp
    src/utilities/math/vectorMath.cpp
    src/utilities/normalization/minMax.cpp
    src/utilities/normalization/signBit.cpp
    src/utilities/normalization/zscore.cpp
    src/utilities/polarization/eigenPolarizer.cpp
    src/utilities/polarization/svdPolarizer.cpp
    src/utilities/rotate/utilities.cpp
    src/utilities/transforms/continuousWavelet.cpp
    src/utilities/transforms/dft.cpp
    src/utilities/transforms/dftRealToComplex.cpp
    src/utilities/transforms/dftUtils.cpp
    src/utilities/transforms/hilbert.cpp
    src/utilities/transforms/envelope.cpp
    src/utilities/transforms/firEnvelope.cpp
    src/utilities/transforms/slidingWindowRealDFT.cpp
    src/utilities/transforms/slidingWindowRealDFTParameters.cpp
    src/utilities/transforms/welch.cpp
    src/utilities/transforms/wavelets/morlet.cpp
    src/utilities/trigger/waterLevel.cpp)

SET(MODULES_SRCS src/modules/detrend.cpp src/modules/demean.cpp)

SET(PROCESSING_SRCS src/postProcessing/singleChannel/waveform.cpp src/postProcessing/singleChannel/taper.cpp)
SET(SRCS ${DATA_SRCS} ${IPPS_SRCS} ${UTILS_SRCS} ${MODULES_SRCS} ${PROCESSING_SRCS})

if(BUILD_SHARED_LIBS)
   add_library(rtseis SHARED ${SRCS})
else()
   add_library(rtseis STATIC ${SRCS})
endif()
target_include_directories(rtseis PRIVATE ${PRIVATE_INCLUDE_DEPENDS})
target_link_libraries(rtseis PRIVATE ${LIBALL})

#########################################################################################
#                                        Unit Tests                                     #
#########################################################################################

if(ADD_TEST)
ADD_EXECUTABLE(utilityTests
               testing/utils/main.cpp
               testing/utils/polynomial.cpp
               testing/utils/interpolate.cpp
               testing/utils/windowFunctions.cpp
               testing/utils/normalization.cpp
               testing/utils/iirDesign.cpp
               testing/utils/firDesign.cpp
               testing/utils/convolve.cpp
               testing/utils/filters.cpp
               testing/utils/wavelets.cpp
               testing/utils/transforms.cpp
               testing/utils/characteristicFunction.cpp
               testing/utils/response.cpp
               testing/utils/rotate.cpp
               testing/utils/polarization.cpp
               testing/utils/trigger.cpp)
ADD_EXECUTABLE(testPPSC
               testing/postProcessing/singleChannel.cpp)

target_link_libraries(utilityTests PRIVATE rtseis ${MKL_LIBRARY} ${IPP_LIBRARY} ${GTEST_BOTH_LIBRARIES})
target_include_directories(utilityTests PRIVATE ${PRIVATE_INCLUDE_DEPENDS} ${GTEST_INCLUDE_DIRS})
target_link_libraries(testPPSC PRIVATE rtseis ${MKL_LIBRARY} ${IPP_LIBRARY} ${GTEST_BOTH_LIBRARIES})
target_include_directories(testPPSC PRIVATE ${PRIVATE_INCLUDE_DEPENDS} ${GTEST_INCLUDE_DIRS})

add_test(NAME utilities
        WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/testing
        COMMAND utilityTests)
add_test(NAME singleChannlePostProcessing
        WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/testing
        COMMAND testPPSC
        DEPENDS utils)

# Need to copy the answers to the test directory
file(COPY ${CMAKE_CURRENT_LIST_DIR}/testing/data DESTINATION .)
file(COPY ${CMAKE_CURRENT_LIST_DIR}/python/benchmarks.py DESTINATION .)
endif()

#========================================================================================#
#                                      Installation                                      #
#========================================================================================#
include(GNUInstallDirs)
if (RTSEIS_WRAP_PYTHON)
   install(TARGETS rtseis pyrtseis
           RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
           LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
           ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
           PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
else()
   install(TARGETS rtseis
           RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
           LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
           ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
           PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
endif()

##########################################################################################
#                                     CPACK Packaging                                    #
##########################################################################################
set(CPACK_PACKAGE_NAME "rtseis")
set(CPACK_PACKAGE_VENDOR "UUSS")
set(CPACK_PACKAGE_CONTACT "bbaker@seis.utah.edu")
set(CPACK_PACKAGE_LICENSE "MIT")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "A real-time seismic signals processing library")
set(CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
set(CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR})
set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH})
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")